package com.ydy.service.book.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ydy.constant.SystemConstant;
import com.ydy.dto.RecordDTO;
import com.ydy.dto.TimeQuantumDTO;
import com.ydy.exception.BusinessException;
import com.ydy.exception.DataNotFoundException;
import com.ydy.exception.ValidateException;
import com.ydy.ienum.EnumBook;
import com.ydy.ienum.EnumOrder;
import com.ydy.ienum.EnumShop;
import com.ydy.ienum.EnumTimeQuantum;
import com.ydy.mapper.BookMapper;
import com.ydy.mapper.BookRecordMapper;
import com.ydy.mapper.OrderMapper;
import com.ydy.mapper.ShopMapper;
import com.ydy.mapper.TimeQuantumMapper;
import com.ydy.model.Book;
import com.ydy.model.BookRecord;
import com.ydy.model.Order;
import com.ydy.model.Shop;
import com.ydy.model.Staff;
import com.ydy.model.TimeQuantum;
import com.ydy.model.User;
import com.ydy.service.book.BookService;
import com.ydy.utils.DateUtil;
import com.ydy.utils.ValidateUtil;
import com.ydy.vo.other.BaseVo;
import com.ydy.vo.other.PageVo;
import com.ydy.vo.other.ResultVo;

@Service
@Transactional
public class BookServiceImpl implements BookService {

	private final static Logger log = LoggerFactory.getLogger(BookServiceImpl.class);

	private static final String LOCK_KEY = "TQ";
	@Autowired
	private BookMapper bookMapper;
	@Autowired
	private BookRecordMapper bookRecordMapper;
	@Autowired
	private ShopMapper shopMapper;
	@Autowired
	private OrderMapper orderMapper;
	@Autowired
	private TimeQuantumMapper timeQuantumMapper;

	@Override
	public PageVo<Book> select(Book book, Staff staff, Integer page, Integer size) {
		book.setShopId(staff.getShopId());
		PageVo<Book> vo = new PageVo<Book>(page, size);
		Page<Book> pageBean = PageHelper.startPage(vo.getPage(), vo.getSize(), "create_time desc");
		List<Book> list = bookMapper.select(book);
		vo.setTotal(pageBean.getTotal());
		vo.setList(list);
		return vo;
	}

	@Override
	public PageVo<Book> list(Book book, User user, Integer page, Integer size) {
		book.setUserId(user.getId());
		PageVo<Book> vo = new PageVo<Book>(page, size);
		Page<Book> pageBean = PageHelper.startPage(vo.getPage(), vo.getSize(), "create_time desc");
		List<Book> list = bookMapper.select(book);
		vo.setTotal(pageBean.getTotal());
		vo.setList(list);
		return vo;
	}

	public String getLock(Book book) {
		String key = LOCK_KEY + book.getShopId() + DateUtil.getDateFile(book.getBookTime());// 作为同步锁
		return key.intern();
	}

	@Override
	public Book save(Book book, User user) {
		if (book == null) {
			throw new NullPointerException();
		}
		book.setUserId(user.getId());
		// 校验数据有效
		Map<String, String> validateInfo = ValidateUtil.validateEntity(book);
		if (!validateInfo.isEmpty()) {
			throw new ValidateException(validateInfo);
		}
		TimeQuantum timeQuantum = timeQuantumMapper.selectByPrimaryKey(book.getTimeQuantumId());
		if (timeQuantum == null) {
			throw new DataNotFoundException(EnumTimeQuantum.DATA_NOT_FOUND);
		}
		Shop shop = shopMapper.selectByPrimaryKey(timeQuantum.getShopId());
		if (shop == null) {
			throw new DataNotFoundException(EnumShop.DATA_NOT_FOUND);
		}
		if (!SystemConstant.USE_STATUS_ON.equals(shop.getOnStatus())) {
			throw new BusinessException(EnumShop.SHOP_CAN_NOT_USE);
		}
		book.setShopId(shop.getId());
		Date bookTime = book.getBookTime();
		Date now = new Date();
		if (DateUtil.isSameToday(bookTime, now)) {// 如果是同一天还要判断时分
			boolean flag = true;
			if (timeQuantum.getStartTimeHour() > DateUtil.getHour(now)) {// 判断小时
				flag = false;
			} else if (timeQuantum.getStartTimeHour().equals(DateUtil.getHour(now))) {// 一样小时就判断分钟
				if (timeQuantum.getStartTimeMinute() > DateUtil.getMinute(now)) {
					flag = false;
				}
			}
			if (flag) {
				throw new BusinessException(EnumBook.BOOK_PASS_TODAY_TIME);
			}
		} else if (now.after(bookTime)) {
			throw new BusinessException(EnumBook.BOOK_PASS);
		}
		if (DateUtil.betweenDays(now, bookTime) > shop.getCanBookDay()) {
			throw new BusinessException(EnumBook.BOOK_TIME_LONG);
		}
		Book b = new Book();
		b.setOrderId(book.getOrderId());
		if (bookMapper.selectCount(b) > 0) {
			log.info("订单{}已预约" + book.getOrderId());
			throw new BusinessException(EnumBook.HAD_BOOK);
		}
		Order order = orderMapper.selectDetail(book.getOrderId());
		if (order == null) {
			throw new DataNotFoundException(EnumOrder.ORDER_NOT_FOUND);
		}
		if (!user.getId().equals(order.getUserId())) {
			throw new BusinessException(EnumOrder.ORDER_NOT_FIT_USER);
		}
		if (!order.getShopId().equals(book.getShopId())) {
			throw new BusinessException(EnumOrder.ORDER_SHOP_NOT_FIT);
		}
		synchronized (getLock(book)) {
			PageHelper.startPage(1, 1, false);
			BookRecord recordExample = new BookRecord();
			recordExample.setShopId(book.getShopId());
			recordExample.setBookDate(bookTime);
			BookRecord record = bookRecordMapper.selectOne(recordExample);
			int count = 0;
			if (record == null) {
				record = new BookRecord();
				record.setShopId(book.getShopId());
				record.setBookDate(bookTime);
				record.setCreateTime(now);
				record.setTotal(0);
				record.setRecord("{}");
				bookRecordMapper.insertSelective(record);
			}
			String json = record.getRecord();
			int total = 0;
			BookRecord newRecord = null;
			{
				RecordDTO recordDTO = JSON.parseObject(json, RecordDTO.class);
				TimeQuantumDTO dto = null;
				if (!CollectionUtils.isEmpty(recordDTO.getList())) {
					for (TimeQuantumDTO t : recordDTO.getList()) {
						total += t.getTotal();
						if (t.getId().equals(timeQuantum.getId())) {
							dto = t;
						}
					}
				}
				if (dto == null) {
					dto = new TimeQuantumDTO();
					dto.setId(timeQuantum.getId());
					dto.setMaxBook(timeQuantum.getMaxBook());
					count = 0;
					dto.setTotal(1);
					recordDTO.add(dto);
				} else {
					count = dto.getTotal();
					dto.setTotal(dto.getTotal() + 1);
				}
				newRecord = new BookRecord();
				newRecord.setId(record.getId());
				newRecord.setTotal(total + 1);
				newRecord.setRecord(JSONObject.toJSONString(recordDTO));
			}
			if (count >= timeQuantum.getMaxBook()) {
				throw new BusinessException(EnumBook.BOOK_FULL);
			}
			bookRecordMapper.updateByPrimaryKeySelective(newRecord);
			// 新增信息
			book.setName(order.getName());
			String timeName = DateUtil.getDateFile(book.getBookTime()) + " " + timeQuantum.toTimeString();
			book.setTimeQuantum(timeName);
			book.setCreateTime(now);
			bookMapper.insertSelective(book);
			log.info("保存book成功：" + book.getId());
		}
		return book;
	}

	@Override
	public BaseVo delete(Long id, User user) {
		if (id == null) {
			throw new NullPointerException();
		}
		Book temp = bookMapper.selectByPrimaryKey(id);
		if (temp == null) {
			log.info("找不到book信息：" + id);
			throw new DataNotFoundException(EnumBook.DATA_NOT_FOUND);
		}
		if (user != null && !user.getId().equals(temp.getUserId())) {
			throw new BusinessException(EnumBook.BOOK_NOT_FIT_USER);
		}
		synchronized (getLock(temp)) {
			PageHelper.startPage(1, 1, false);
			BookRecord recordExample = new BookRecord();
			recordExample.setShopId(temp.getShopId());
			recordExample.setBookDate(temp.getBookTime());
			BookRecord record = bookRecordMapper.selectOne(recordExample);
			String json = record.getRecord();
			int total = 0;
			BookRecord newRecord = null;
			{
				RecordDTO recordDTO = JSON.parseObject(json, RecordDTO.class);
				TimeQuantumDTO dto = null;
				if (!CollectionUtils.isEmpty(recordDTO.getList())) {
					for (TimeQuantumDTO t : recordDTO.getList()) {
						total += t.getTotal();
						if (t.getId().equals(temp.getTimeQuantumId())) {
							dto = t;
						}
					}
				}
				dto.setTotal(dto.getTotal() - 1);
				newRecord = new BookRecord();
				newRecord.setId(record.getId());
				newRecord.setTotal(total - 1);
				newRecord.setRecord(JSONObject.toJSONString(recordDTO));
			}
			bookRecordMapper.updateByPrimaryKeySelective(newRecord);
			bookMapper.deleteByPrimaryKey(id);
			log.info("删除book成功：" + id);
		}
		return new ResultVo();
	}

	@Override
	public Book selectById(Long id) {
		if (id == null) {
			throw new NullPointerException();
		}
		Book temp = bookMapper.selectByPrimaryKey(id);
		if (temp == null) {
			throw new BusinessException(EnumBook.DATA_NOT_FOUND);
		}
		return temp;
	}
}
